#include "Joystick.hpp"

const OIS::JoyStick* OgreMax::Joystick::GetJoystick() const
{
    return this->joystick;
}

bool OgreMax::Joystick::IsNull() const
{
    return this->joystick == 0;
}

bool OgreMax::Joystick::PressedButton(int button) const
{
    return
        this->joystick != 0 &&
        button < (int)this->previousJoystickState.mButtons.size() &&
        !this->previousJoystickState.mButtons[button] &&
        this->joystick->getJoyStickState().mButtons[button];
}

bool OgreMax::Joystick::PressingButton(int button) const
{
    return
        this->joystick != 0 &&
        button < (int)this->previousJoystickState.mButtons.size() &&
        this->joystick->getJoyStickState().mButtons[button];
}

bool OgreMax::Joystick::ReleasedButton(int button) const
{
    return
        this->joystick != 0 &&
        button < (int)this->previousJoystickState.mButtons.size() &&
        this->previousJoystickState.mButtons[button] &&
        !this->joystick->getJoyStickState().mButtons[button];
}

bool OgreMax::Joystick::PressedAnyButton() const
{
    for (int buttonIndex = 0; buttonIndex < BUTTON_COUNT; buttonIndex++)
    {
        if (PressedButton(buttonIndex))
            return true;
    }
    return false;
}

bool OgreMax::Joystick::PressingAnyButton() const
{
    if (this->joystick != 0)
    {
        const OIS::JoyStickState& joystickState = this->joystick->getJoyStickState();
        for (int buttonIndex = 0; buttonIndex < (int)joystickState.mButtons.size(); buttonIndex++)
        {
            if (joystickState.mButtons[buttonIndex])
                return true;
        }
    }
    return false;
}

bool OgreMax::Joystick::ReleasedAnyButton() const
{
    for (int buttonIndex = 0; buttonIndex < BUTTON_COUNT; buttonIndex++)
    {
        if (ReleasedButton(buttonIndex))
            return true;
    }
    return false;
}

bool OgreMax::Joystick::PressedAxis(int axis, int direction, int deadZone) const
{
    return
        this->joystick != 0 &&
        axis < (int)this->joystick->getJoyStickState().mAxes.size() &&
        !AxisActive(this->previousJoystickState.mAxes[axis].abs, direction, deadZone) &&
        AxisActive(this->joystick->getJoyStickState().mAxes[axis].abs, direction, deadZone);
}

bool OgreMax::Joystick::PressingAxis(int axis, int direction, int deadZone) const
{
    return
        this->joystick != 0 &&
        axis < (int)this->joystick->getJoyStickState().mAxes.size() &&
        AxisActive(this->joystick->getJoyStickState().mAxes[axis].abs, direction, deadZone);
}

bool OgreMax::Joystick::ReleasedAxis(int axis, int direction, int deadZone) const
{
    return
        this->joystick != 0 &&
        axis < (int)this->joystick->getJoyStickState().mAxes.size() &&
        AxisActive(this->previousJoystickState.mAxes[axis].abs, direction, deadZone) &&
        !AxisActive(this->joystick->getJoyStickState().mAxes[axis].abs, direction, deadZone);
}

bool OgreMax::Joystick::PressedAnyAxis() const
{
    if (this->joystick != 0)
    {
        const OIS::JoyStickState& joystickState = this->joystick->getJoyStickState();

        for (size_t axisIndex = 0; axisIndex < joystickState.mAxes.size(); axisIndex++)
        {
            if (!AxisActive(joystickState.mAxes[axisIndex].abs, DEFAULT_DEAD_ZONE) &&
                AxisActive(joystickState.mAxes[axisIndex].abs, DEFAULT_DEAD_ZONE))
            {
                return true;
            }
        }
    }

    return false;
}

bool OgreMax::Joystick::PressingAnyAxis() const
{
    if (this->joystick != 0)
    {
        const OIS::JoyStickState& joystickState = this->joystick->getJoyStickState();

        for (size_t axisIndex = 0; axisIndex < joystickState.mAxes.size(); axisIndex++)
        {
            if (AxisActive(joystickState.mAxes[axisIndex].abs, DEFAULT_DEAD_ZONE))
                return true;
        }
    }

    return false;
}

bool OgreMax::Joystick::ReleasedAnyAxis() const
{
    if (this->joystick != 0)
    {
        const OIS::JoyStickState& joystickState = this->joystick->getJoyStickState();

        for (size_t axisIndex = 0; axisIndex < joystickState.mAxes.size(); axisIndex++)
        {
            if (AxisActive(joystickState.mAxes[axisIndex].abs, DEFAULT_DEAD_ZONE) &&
                !AxisActive(joystickState.mAxes[axisIndex].abs, DEFAULT_DEAD_ZONE))
            {
                return true;
            }
        }
    }

    return false;
}

bool OgreMax::Joystick::PressedPov(int povIndex, int povDirection, bool strict /*= false*/) const
{
    bool result = false;
    if (this->joystick != 0 && povIndex < POV_COUNT)
    {
        if (strict)
        {
            result =
                this->previousJoystickState.mPOV[povIndex].direction != povDirection &&
                this->joystick->getJoyStickState().mPOV[povIndex].direction == povDirection;
        }
        else
        {
            result =
                !(this->previousJoystickState.mPOV[povIndex].direction & povDirection) &&
                this->joystick->getJoyStickState().mPOV[povIndex].direction & povDirection;
        }
    }
    return result;
}

bool OgreMax::Joystick::PressingPov(int povIndex, int povDirection, bool strict /*= false*/) const
{
    bool result = false;
    if (this->joystick != 0 && povIndex < POV_COUNT)
    {
        if (strict)
            result = this->joystick->getJoyStickState().mPOV[povIndex].direction == povDirection;
        else
            result = (this->joystick->getJoyStickState().mPOV[povIndex].direction & povDirection) != 0;
    }
    return result;
}

bool OgreMax::Joystick::ReleasedPov(int povIndex, int povDirection, bool strict /*= false*/) const
{
    bool result = false;
    if (this->joystick != 0 && povIndex < POV_COUNT)
    {
        if (strict)
        {
            result =
                this->previousJoystickState.mPOV[povIndex].direction == povDirection &&
                this->joystick->getJoyStickState().mPOV[povIndex].direction != povDirection;
        }
        else
        {
            result =
                (this->previousJoystickState.mPOV[povIndex].direction & povDirection) &&
                !(this->joystick->getJoyStickState().mPOV[povIndex].direction & povDirection);
        }
    }
    return result;
}

bool OgreMax::Joystick::PressedAnyPov() const
{
    if (this->joystick != 0)
    {
        const OIS::JoyStickState& joystickState = this->joystick->getJoyStickState();

        for (size_t povIndex = 0; povIndex < POV_COUNT; povIndex++)
        {
            if ((this->previousJoystickState.mPOV[povIndex].direction == 0 || this->previousJoystickState.mPOV[povIndex].direction != joystickState.mPOV[povIndex].direction) &&
                joystickState.mPOV[povIndex].direction != 0)
            {
                return true;
            }
        }
    }

    return false;
}

bool OgreMax::Joystick::PressingAnyPov() const
{
    if (this->joystick != 0)
    {
        const OIS::JoyStickState& joystickState = this->joystick->getJoyStickState();

        for (size_t povIndex = 0; povIndex < POV_COUNT; povIndex++)
        {
            if (joystickState.mPOV[povIndex].direction != 0)
                return true;
        }
    }

    return false;
}

bool OgreMax::Joystick::ReleasedAnyPov() const
{
    if (this->joystick != 0)
    {
        const OIS::JoyStickState& joystickState = this->joystick->getJoyStickState();

        for (size_t povIndex = 0; povIndex < POV_COUNT; povIndex++)
        {
            if ((joystickState.mPOV[povIndex].direction == 0 || this->previousJoystickState.mPOV[povIndex].direction != joystickState.mPOV[povIndex].direction) &&
                this->previousJoystickState.mPOV[povIndex].direction != 0)
            {
                return true;
            }
        }
    }

    return false;
}

int OgreMax::Joystick::GetPressedButton() const
{
    for (int buttonIndex = 0; buttonIndex < BUTTON_COUNT; buttonIndex++)
    {
        if (PressedButton(buttonIndex))
            return buttonIndex;
    }

    return -1;
}

int OgreMax::Joystick::GetPressingButton() const
{
    for (int buttonIndex = 0; buttonIndex < BUTTON_COUNT; buttonIndex++)
    {
        if (PressingButton(buttonIndex))
            return buttonIndex;
    }

    return -1;
}

int OgreMax::Joystick::GetReleasedButton() const
{
    for (int buttonIndex = 0; buttonIndex < BUTTON_COUNT; buttonIndex++)
    {
        if (ReleasedButton(buttonIndex))
            return buttonIndex;
    }

    return -1;
}

bool OgreMax::Joystick::GetPressedAxisIndexAndDirection(int& index, int& direction) const
{
    if (this->joystick != 0)
    {
        const OIS::JoyStickState& joystickState = this->joystick->getJoyStickState();

        for (int axisIndex = 0; axisIndex < (int)joystickState.mAxes.size(); axisIndex++)
        {
            if (PressedAxis(axisIndex, 0, Joystick::DEFAULT_DEAD_ZONE))
            {
                index = axisIndex;
                direction = (joystickState.mAxes[axisIndex].abs < 0) ? -1 : 1;
                return true;
            }
        }
    }

    return false;
}

bool OgreMax::Joystick::GetPressingAxisIndexAndDirection(int& index, int& direction) const
{
    if (this->joystick != 0)
    {
        const OIS::JoyStickState& joystickState = this->joystick->getJoyStickState();

        for (int axisIndex = 0; axisIndex < (int)joystickState.mAxes.size(); axisIndex++)
        {
            if (PressingAxis(axisIndex, 0, Joystick::DEFAULT_DEAD_ZONE))
            {
                index = axisIndex;
                direction = (joystickState.mAxes[axisIndex].abs < 0) ? -1 : 1;
                return true;
            }
        }
    }

    return false;
}

bool OgreMax::Joystick::GetReleasedAxisIndexAndDirection(int& index, int& direction) const
{
    if (this->joystick != 0)
    {
        const OIS::JoyStickState& joystickState = this->joystick->getJoyStickState();

        for (int axisIndex = 0; axisIndex < (int)joystickState.mAxes.size(); axisIndex++)
        {
            if (ReleasedAxis(axisIndex, 0, Joystick::DEFAULT_DEAD_ZONE))
            {
                index = axisIndex;
                direction = (joystickState.mAxes[axisIndex].abs < 0) ? -1 : 1;
                return true;
            }
        }
    }

    return false;
}

bool OgreMax::Joystick::GetPressedPovIndexAndDirection(int& index, int& direction) const
{
    if (this->joystick != 0)
    {
        const OIS::JoyStickState& joystickState = this->joystick->getJoyStickState();

        for (int povIndex = 0; povIndex < POV_COUNT; povIndex++)
        {
            if ((this->previousJoystickState.mPOV[povIndex].direction == 0 || this->previousJoystickState.mPOV[povIndex].direction != joystickState.mPOV[povIndex].direction) &&
                joystickState.mPOV[povIndex].direction != 0)
            {
                index = povIndex;
                direction = joystickState.mPOV[povIndex].direction;
                return true;
            }
        }
    }

    return false;
}

bool OgreMax::Joystick::GetPressingPovIndexAndDirection(int& index, int& direction) const
{
    if (this->joystick != 0)
    {
        const OIS::JoyStickState& joystickState = this->joystick->getJoyStickState();

        for (int povIndex = 0; povIndex < POV_COUNT; povIndex++)
        {
            if (joystickState.mPOV[povIndex].direction != 0)
            {
                index = povIndex;
                direction = joystickState.mPOV[povIndex].direction;
                return true;
            }
        }
    }

    return false;
}

bool OgreMax::Joystick::GetReleasedPovIndexAndDirection(int& index, int& direction) const
{
    if (this->joystick != 0)
    {
        const OIS::JoyStickState& joystickState = this->joystick->getJoyStickState();

        for (int povIndex = 0; povIndex < POV_COUNT; povIndex++)
        {
            if ((joystickState.mPOV[povIndex].direction == 0 || this->previousJoystickState.mPOV[povIndex].direction != joystickState.mPOV[povIndex].direction) &&
                this->previousJoystickState.mPOV[povIndex].direction != 0)
            {
                index = povIndex;
                direction = joystickState.mPOV[povIndex].direction;
                return true;
            }
        }
    }

    return false;
}

void OgreMax::Joystick::GetPressedButtons(InputSourceVector& inputSources) const
{
    InputSource inputSource;
    inputSource.deviceType = InputSource::JOYSTICK_BUTTON;
    for (inputSource.button = 0; inputSource.button < BUTTON_COUNT; inputSource.button++)
    {
        if (PressedButton(inputSource.button))
            inputSources.push_back(inputSource);
    }
}

void OgreMax::Joystick::GetPressingButtons(InputSourceVector& inputSources) const
{
    InputSource inputSource;
    inputSource.deviceType = InputSource::JOYSTICK_BUTTON;
    for (inputSource.button = 0; inputSource.button < BUTTON_COUNT; inputSource.button++)
    {
        if (PressingButton(inputSource.button))
            inputSources.push_back(inputSource);
    }
}

void OgreMax::Joystick::GetReleasedButtons(InputSourceVector& inputSources) const
{
    InputSource inputSource;
    inputSource.deviceType = InputSource::JOYSTICK_BUTTON;
    for (inputSource.button = 0; inputSource.button < BUTTON_COUNT; inputSource.button++)
    {
        if (ReleasedButton(inputSource.button))
            inputSources.push_back(inputSource);
    }
}

void OgreMax::Joystick::GetPressedAxisIndicesAndDirections(InputSourceVector& inputSources) const
{
    if (this->joystick != 0)
    {
        const OIS::JoyStickState& joystickState = this->joystick->getJoyStickState();
        InputSource inputSource;
        inputSource.deviceType = InputSource::JOYSTICK_AXIS;
        for (inputSource.axis = 0; inputSource.axis < (int)joystickState.mAxes.size(); inputSource.axis++)
        {
            if (PressedAxis(inputSource.axis, 0, Joystick::DEFAULT_DEAD_ZONE))
            {
                inputSource.direction = (joystickState.mAxes[inputSource.axis].abs < 0) ? -1 : 1;
                inputSources.push_back(inputSource);
            }
        }
    }
}

void OgreMax::Joystick::GetPressingAxisIndicesAndDirections(InputSourceVector& inputSources) const
{
    if (this->joystick != 0)
    {
        const OIS::JoyStickState& joystickState = this->joystick->getJoyStickState();
        InputSource inputSource;
        inputSource.deviceType = InputSource::JOYSTICK_AXIS;
        for (inputSource.axis = 0; inputSource.axis < (int)joystickState.mAxes.size(); inputSource.axis++)
        {
            if (PressingAxis(inputSource.axis, 0, Joystick::DEFAULT_DEAD_ZONE))
            {
                inputSource.direction = (joystickState.mAxes[inputSource.axis].abs < 0) ? -1 : 1;
                inputSources.push_back(inputSource);
            }
        }
    }
}

void OgreMax::Joystick::GetReleasedAxisIndicesAndDirections(InputSourceVector& inputSources) const
{
    if (this->joystick != 0)
    {
        const OIS::JoyStickState& joystickState = this->joystick->getJoyStickState();
        InputSource inputSource;
        inputSource.deviceType = InputSource::JOYSTICK_AXIS;
        for (inputSource.axis = 0; inputSource.axis < (int)joystickState.mAxes.size(); inputSource.axis++)
        {
            if (ReleasedAxis(inputSource.axis, 0, Joystick::DEFAULT_DEAD_ZONE))
            {
                inputSource.direction = (joystickState.mAxes[inputSource.axis].abs < 0) ? -1 : 1;
                inputSources.push_back(inputSource);
            }
        }
    }
}

void OgreMax::Joystick::GetPressedPovIndicesAndDirections(InputSourceVector& inputSources) const
{
    if (this->joystick != 0)
    {
        const OIS::JoyStickState& joystickState = this->joystick->getJoyStickState();
        InputSource inputSource;
        inputSource.deviceType = InputSource::JOYSTICK_POV;
        for (inputSource.povIndex = 0; inputSource.povIndex < POV_COUNT; inputSource.povIndex++)
        {
            if ((this->previousJoystickState.mPOV[inputSource.povIndex].direction == 0 || this->previousJoystickState.mPOV[inputSource.povIndex].direction != joystickState.mPOV[inputSource.povIndex].direction) &&
                joystickState.mPOV[inputSource.povIndex].direction != 0)
            {
                inputSource.direction = joystickState.mPOV[inputSource.povIndex].direction;
                inputSources.push_back(inputSource);
            }
        }
    }
}

void OgreMax::Joystick::GetPressingPovIndicesAndDirections(InputSourceVector& inputSources) const
{
    if (this->joystick != 0)
    {
        const OIS::JoyStickState& joystickState = this->joystick->getJoyStickState();
        InputSource inputSource;
        inputSource.deviceType = InputSource::JOYSTICK_POV;
        for (inputSource.povIndex = 0; inputSource.povIndex < POV_COUNT; inputSource.povIndex++)
        {
            if ((this->previousJoystickState.mPOV[inputSource.povIndex].direction == 0 || this->previousJoystickState.mPOV[inputSource.povIndex].direction != joystickState.mPOV[inputSource.povIndex].direction) &&
                joystickState.mPOV[inputSource.povIndex].direction != 0)
            {
                inputSource.direction = joystickState.mPOV[inputSource.povIndex].direction;
                inputSources.push_back(inputSource);
            }
        }
    }
}

void OgreMax::Joystick::GetReleasedPovIndicesAndDirections(InputSourceVector& inputSources) const
{
    if (this->joystick != 0)
    {
        const OIS::JoyStickState& joystickState = this->joystick->getJoyStickState();
        InputSource inputSource;
        inputSource.deviceType = InputSource::JOYSTICK_POV;
        for (inputSource.povIndex = 0; inputSource.povIndex < POV_COUNT; inputSource.povIndex++)
        {
            if ((this->previousJoystickState.mPOV[inputSource.povIndex].direction == 0 || this->previousJoystickState.mPOV[inputSource.povIndex].direction != joystickState.mPOV[inputSource.povIndex].direction) &&
                joystickState.mPOV[inputSource.povIndex].direction != 0)
            {
                inputSource.direction = joystickState.mPOV[inputSource.povIndex].direction;
                inputSources.push_back(inputSource);
            }
        }
    }
}

OgreMax::Joystick::Joystick()
{
    this->joystick = 0;
    this->updatedOnce = false;
}

void OgreMax::Joystick::Set(OIS::JoyStick* joystick)
{
    this->joystick = joystick;
    this->updatedOnce = false;
}

void OgreMax::Joystick::Update()
{
    if (this->joystick != 0)
    {
        //Save current state as the previous state
        this->previousJoystickState = this->joystick->getJoyStickState();

        //Get new state
        this->joystick->capture();

        //Copy current state to previous state if this is the first update
        if (!this->updatedOnce)
        {
            this->previousJoystickState = this->joystick->getJoyStickState();
            this->updatedOnce = true;
        }
    }
}

bool OgreMax::Joystick::AxisActive(int value, int direction, int deadZone)
{
    if (direction == 0)
        return std::abs(value) > deadZone;
    else
        return value * direction > deadZone;
}

bool OgreMax::Joystick::AxisActive(int value, int deadZone)
{
    return std::abs(value) > deadZone;
}

const OIS::Axis& OgreMax::Joystick::GetJoystickAxis(const OIS::JoyStickState& joystickState, int axis)
{
    static OIS::Axis nullAxis;

    if (axis < (int)joystickState.mAxes.size())
        return joystickState.mAxes[axis];
    else
        return nullAxis;
}